package com.szwistar.common.comm;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UdpUtils {
	static final Logger LOG = LoggerFactory.getLogger(UdpUtils.class);
	public static InetAddress ADDR_BROADCAST;
	public static InetAddress ADDR_LOCAL_ALL;

	static {
		try {
			ADDR_BROADCAST = InetAddress.getByName("255.255.255.255");
			ADDR_LOCAL_ALL = InetAddress.getByName("0.0.0.0");
		} catch (UnknownHostException e) {
		}
	}

	static boolean tx(DatagramSocket socket, byte data[], int length, InetAddress remoteAddress, int remotePort) {
		try {
			// 如果未指定目标地址，则使用广播地址
			if(remoteAddress == null) { remoteAddress = UdpUtils.ADDR_BROADCAST; }
			// 构建数据包
			DatagramPacket packet = new DatagramPacket(data, data.length, remoteAddress, remotePort);
	        // 发送
	        socket.send(packet);
	        return true;
		} catch (Exception e) {
			LOG.error("发送数据失败！", e);
			return false;
		}
	}

	static boolean rx(DatagramSocket socket, UdpPacketHandler handler, int timeout) {
        if(handler == null) { return false; }
		byte[] data = new byte[4096];
		DatagramPacket packet = new DatagramPacket(data, data.length);
		boolean ret = false;

        while(true) {
			try {
				// 接收，直到超时
		        socket.receive(packet);
		        // 调用回调函数处理
		        ret = handler.onPacket(packet);
			} catch (Exception e) {
				if(e instanceof SocketTimeoutException) { return ret; }
				LOG.error("接收配置数据失败！", e);
				return false;
			}
        }
	}

	/**
	 * 发送/接收数据帧
	 */
	public static boolean txrx(byte data[], int length, InetAddress remoteAddress, int remotePort, InetAddress localAddress, int localPort, int timeout, UdpPacketHandler handler) {
    	DatagramSocket socket = null;
    	boolean ret = true;

    	try {
			// 绑定接收端口
    		if(localAddress == null) {
    			socket = new DatagramSocket(localPort);
    		} else {
    			socket = new DatagramSocket(localPort, localAddress);
    		}
	        // 注意：一定要设置接收超时时间，否则会永久阻塞！！！
	        socket.setSoTimeout(timeout);
		} catch (Exception e) {
			LOG.error("创建 UDP Socket 失败！", e);
			return false;
		}

    	if(!tx(socket, data, length, remoteAddress, remotePort)) { return false; }
	    ret = rx(socket, handler, timeout);

		// 释放socket
		if(socket != null) { socket.close(); socket = null; }
		return ret;
	}
}
